#pragma once

#include <experimental/filesystem>
#include <memory>
#include <functional>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>

#include "zrpc/base/logger.h"

namespace zrpc {

class AsyncLogging {
 public:
  AsyncLogging(std::string file_path, std::string base_name, size_t roll_size,
               int32_t interval = 3);

  ~AsyncLogging() {
    if (running_) {
      Stop();
    }
  }

  void Stop() {
    running_ = false;
    condition_.notify_one();
  }

  void Start() {
    std::thread t(std::bind(&AsyncLogging::ThreadFunc, this));
    t.detach();
  }

  void Append(const char *loline, size_t len);

 private:
  AsyncLogging(const AsyncLogging &);

  void operator=(const AsyncLogging &);

  void ThreadFunc();

  typedef FixedBuffer<kLargeBuffer> Buffer;
  typedef std::vector<std::unique_ptr<Buffer>> BufferVector;
  std::string file_path_;
  std::string base_name_;
  const int32_t interval_;
  bool running_;
  size_t roll_size_;
  mutable std::mutex mutex_;
  std::condition_variable condition_;
  std::unique_ptr<Buffer> current_buffer_;
  std::unique_ptr<Buffer> next_buffer_;
  BufferVector buffers_;
};

}  // namespace zrpc